#include "DesktopHelper.h"

///Copyright (c) 2009-2010 T. Klepzig 

DesktopHelper::DesktopHelper(bool refreshDesktopItems)
{
	desktopVMPtr = 0;
	hProcessDesktop = 0;

	if (refreshDesktopItems)
		RefreshDesktopItems();
}

DesktopHelper::~DesktopHelper()
{
	if (!desktopVMPtr && !hProcessDesktop)
	{
		VirtualFreeEx(hProcessDesktop, desktopVMPtr, 0, MEM_RELEASE);
		CloseHandle(hProcessDesktop);
		desktopVMPtr = 0;
		hProcessDesktop = 0;
	}
}

bool DesktopHelper::GetDesktopAlignToGrid()
{
    HWND desktop = Utilities::GetDesktopWindow(Utilities::DW_SysListView32);
    return ((SendMessage(desktop, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0) & LVS_EX_SNAPTOGRID) == LVS_EX_SNAPTOGRID);
}

bool DesktopHelper::GetDesktopAutoArrange()
{
    HWND desktop = Utilities::GetDesktopWindow(Utilities::DW_SysListView32);
	return ((GetWindowLongPtr(desktop, GWL_STYLE) & LVS_AUTOARRANGE) == LVS_AUTOARRANGE);
}

void DesktopHelper::SetDesktopAlignToGrid(bool value)
{
    bool alignToGridActive = GetDesktopAlignToGrid();

    //if toogle is needed
    if (value != alignToGridActive)
    {
		OSVERSIONINFO osvi={0};
		osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
		GetVersionEx(&osvi);

		HWND desktop = Utilities::GetDesktopWindow(Utilities::DW_SHELLDLL_DefViewParent);

		if (osvi.dwMinorVersion == 1) //Seven
			desktop = Utilities::GetDesktopWindow(Utilities::DW_SHELLDLL_DefView);
               
		SendMessage(desktop, WM_COMMAND, 0x7074, 0);
    }
}

void DesktopHelper::SetDesktopAutoArrange(bool value)
{
    bool autoArrangeActive = GetDesktopAutoArrange();

    //if toogle is needed
    if (value != autoArrangeActive)
    {
		OSVERSIONINFO osvi={0};
		osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
		GetVersionEx(&osvi);

		HWND desktop = Utilities::GetDesktopWindow(Utilities::DW_SHELLDLL_DefViewParent);

		if (osvi.dwMinorVersion == 1) //Seven
			desktop = Utilities::GetDesktopWindow(Utilities::DW_SHELLDLL_DefView);

		SendMessage(desktop, WM_COMMAND, 0x7071, 0);
    }
}

int DesktopHelper::GetDesktopItemCount()
{
	return ListView_GetItemCount(Utilities::GetDesktopWindow(Utilities::DW_SysListView32));
}

void DesktopHelper::RefreshDesktop()
{
	OSVERSIONINFO osvi={0};
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&osvi);

	HWND desktop = Utilities::GetDesktopWindow(Utilities::DW_ProgMan);
	
	if (osvi.dwMinorVersion == 1) //Seven
		desktop = Utilities::GetDesktopWindow(Utilities::DW_SHELLDLL_DefView);

    SendMessage(desktop, WM_COMMAND, 0x7103, 0);
}

void DesktopHelper::RefreshDesktopItems()
{
	DesktopItems.clear();

	HWND desktop = Utilities::GetDesktopWindow(Utilities::DW_SysListView32);
	DesktopInfo.HWnd = desktop;

	int iconCount = ListView_GetItemCount(desktop);

	DWORD spacing = ListView_GetItemSpacing(desktop,FALSE);
	DesktopInfo.GridSize.cx = LOWORD(spacing);
	DesktopInfo.GridSize.cy = HIWORD(spacing);

	GetWindowRect(desktop,&DesktopInfo.Bounds);

	SIZE_T numberOfBytesWritten = 0;
    SIZE_T numberOfBytesRead = 0;

    DWORD processId;
    GetWindowThreadProcessId(desktop, &processId);

    hProcessDesktop = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, processId);
	desktopVMPtr = (int*)VirtualAllocEx(hProcessDesktop, 0, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

    for (int i = 0; i < iconCount; i++)
    {
		//fill buffer with icon text
		TCHAR buffer[256]={0};

        LVITEM lvi;
		lvi.mask = LVIF_TEXT;
        lvi.iItem = i;
        lvi.iSubItem = 0;
        lvi.cchTextMax = 255;
        lvi.pszText = (LPTSTR)(desktopVMPtr + sizeof(LVITEM));

        WriteProcessMemory(hProcessDesktop,desktopVMPtr,&lvi,sizeof(LVITEM),&numberOfBytesWritten);
        SendMessage(desktop, LVM_GETITEM, i, (LPARAM)desktopVMPtr);
        ReadProcessMemory(hProcessDesktop,desktopVMPtr + sizeof(LVITEM),&buffer,sizeof(buffer),&numberOfBytesRead);		


		//fill itemBounds with icon bounds
		RECT itemBounds={0};
		SendMessage(desktop, LVM_GETITEMRECT, i, (LPARAM)desktopVMPtr);
		ReadProcessMemory(hProcessDesktop,desktopVMPtr,&itemBounds,sizeof(RECT),&numberOfBytesRead);


		//fill itemPosition with icon position
		POINT itemPosition={0};
		SendMessage(desktop, LVM_GETITEMPOSITION, i, (LPARAM)desktopVMPtr);
		ReadProcessMemory(hProcessDesktop,desktopVMPtr,&itemPosition,sizeof(POINT),&numberOfBytesRead);

		DesktopItem di;
		di.Index = i;
		di.Bounds = itemBounds;
		di.Location = itemPosition;
		di.Text = buffer;

		DesktopItems.insert(di);
    }

    VirtualFreeEx(hProcessDesktop, desktopVMPtr, 0, MEM_RELEASE);
    CloseHandle(hProcessDesktop);
	desktopVMPtr = 0;
	hProcessDesktop = 0;

}
